package main

import (
	"crypto/sha256"
	"fmt"
	"strings"
)

// 计算hash值
func calHash(data []byte) []byte {
	hash := sha256.Sum256(data)
	//fmt.Println("Hash calculated:", hash)
	return hash[:]
}

// 创建merkleTree节点
type MerkleNode struct {
	hash       []byte
	leftChild  *MerkleNode
	rightChild *MerkleNode
}

// 创建叶子节点
func NewMerkleleaf(data []byte) *MerkleNode {
	return &MerkleNode{
		hash: calHash(data),
	}
}

// 创建父节点
func NewMerkleParent(left *MerkleNode, right *MerkleNode) *MerkleNode {
	parent := &MerkleNode{
		leftChild:  left,
		rightChild: right,
	}

	parent.hash = calHash(append(left.hash, right.hash...))
	return parent
}

// 切割字符串
func split(data string) []string {
	var result []string
	result = strings.Split(data, " ")
	return result
}

// 创建叶子节点
// createleaf 函数接收一个字符串 data1，并返回一个 MerkleNode 指针的切片。
func createleaf(data1 string) []*MerkleNode {
	// 将输入的字符串 data1 分割成多个部分，存储在切片 data 中。
	data := split(data1)
	// 初始化一个空的 MerkleNode 指针切片 leafs。
	var leafs []*MerkleNode
	// 如果 data 的长度是奇数，则复制最后一个元素，使其长度变为偶数。
	// 这是为了确保 Merkle 树的每一层都有偶数个节点。
	if len(data)%2 == 1 {
		data = append(data, data[len(data)-1])
	}
	// 遍历 data 切片中的每一个元素。
	for _, v := range data {
		// 将每个元素转换为字节切片，并创建一个新的 MerkleNode 叶子节点。
		// 将新创建的叶子节点添加到 leafs 切片中。
		leafs = append(leafs, NewMerkleleaf([]byte(v)))
	}
	// 返回包含所有叶子节点的切片
	return leafs
}

// 创建父节点
func createLayer(layer []*MerkleNode) []*MerkleNode {
	var root []*MerkleNode
	count := len(layer)
	if count%2 == 0 {
		var i = 0
		for {
			if i <= count/2-1 {
				root = append(root, NewMerkleParent(layer[2*i], layer[2*i+1]))
				i++
			} else {
				break
			}
		}
		return createLayer(root)
	} else {
		root = layer
		return root
	}
}

// 创建merkleTree
// 函数根据输入的数据字符串创建一个默克尔树，并返回默克尔树的节点数组。
func createMerkleTree(data1 string) []*MerkleNode {
	leafs := createleaf(data1)
	return createLayer(leafs)
}

// 打印merkleTree
// printMerkleTree函数递归地打印Merkle树的节点哈希值
// 参数root是Merkle树的根节点指针
func printMerkleTree(root *MerkleNode) {
	if root == nil {
		return
	}
	//printMerkleTree(root.leftChild)
	fmt.Println(root.hash)
	//printMerkleTree(root.rightChild)
}

// main函数
func main() {
	data1 := "xunzhangjunhaoshuai"
	tree := createMerkleTree(data1)
	printMerkleTree(tree[0])
}
